package com.zhan.rkforum.service;

import com.zhan.rkforum.bean.LoginTicket;
import com.zhan.rkforum.bean.User;
import com.zhan.rkforum.dao.LoginTicketMapper;
import com.zhan.rkforum.dao.UserMapper;
import com.zhan.rkforum.util.CommunityConstant;
import com.zhan.rkforum.util.CommunityUtil;
import com.zhan.rkforum.util.MailUtil;
import com.zhan.rkforum.util.RedisKeyUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;

import java.util.*;
import java.util.concurrent.TimeUnit;


@Service
@Transactional
public class UserServiceImpl implements UserService, CommunityConstant{

    private final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class);


    @Autowired
    private UserMapper userMapper;

    @Value("${community.path.address}")
    private String address;

    @Value("${server.servlet.context-path}")
    private String contextPath;

    @Autowired
    private TemplateEngine templateEngine;

    @Autowired
    private MailUtil mailUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    @Autowired
    private LoginTicketMapper loginTicketMapper;



    @Override
    public User findUserById(int id) {
        User user = getUserInRedisById(id);
        if(ObjectUtils.isEmpty(user)){
            user = initCache(id);
        }
        return user;
    }

    @Override
    public User findUserByName(String username) {
        return userMapper.findUserByUserName(username);
    }

    @Override
    public Map<String, Object> register(User user) {
        HashMap<String, Object> map = new HashMap<>(10);
        //前端传来的user
        if(ObjectUtils.isEmpty(user)) {
            throw new IllegalArgumentException("参数不能为空！");
        }
        if(StringUtils.isBlank(user.getUsername())){
            map.put("usernameMsg","账号不能为空");
            return map;
        }
        if(StringUtils.isBlank(user.getPassword())){
            map.put("passwordMsg","密码不能为空");
            return map;
        }
        if(StringUtils.isBlank(user.getEmail())){
            map.put("emailMsg","邮箱不能为空");
            return map;
        }

        User userByUserName = userMapper.findUserByUserName(user.getUsername());
        if(ObjectUtils.isNotEmpty(userByUserName)){
            map.put("usernameMsg", "用户名已存在");
            return map;
        }


        User userByEmail = userMapper.findUserByEmail(user.getEmail());
        if(ObjectUtils.isNotEmpty(userByEmail)){
            map.put("emailMsg", "邮箱已被注册");
            return map;
        }

        Map<String, String> md5Map = CommunityUtil.parseByMd5(user.getPassword());
        String newPassword = md5Map.get("md5String");
        String salt = md5Map.get("salt");

        user.setPassword(newPassword);
        user.setSalt(salt);
        user.setCreateTime(new Date());
        user.setHeaderUrl(String.format("http://images.nowcoder.com/head/%dt.png", new Random().nextInt(1000)));
        String activationCode = UUID.randomUUID().toString().replace("-", "");
        user.setActivationCode(activationCode);
        user.setType(0);
        //持久化到数据库，完成注册
        userMapper.insertUser(user);
        //发送激活邮件
        Context context = new Context();
        context.setVariable("email",user.getEmail());
        String url = address+ contextPath + "/activation/" + user.getUsername() + "/"+activationCode;
        context.setVariable("url",url);
        //格式化邮件内容
        String content = templateEngine.process("/mail/activation", context);

        mailUtil.sendMail(user.getEmail(),"瑞克论坛",content);
        return map;
    }

    @Override
    public int active(String username, String code) {
        User user = userMapper.findUserByUserName(username);
        if(ObjectUtils.isEmpty(user)) {
            return ACTIVATION_FAILURE;
        }
        if(user.getStatus() == 1) {
            return ACTIVATION_REPEAT;
        }
        if(code.equals(user.getActivationCode())) {
            userMapper.updateStatus(username, 1);
            clearCache(user.getId());
            return ACTIVATION_SUCCESS;
        }
        return ACTIVATION_FAILURE;
    }

    @Override
    public Map<String, Object> login(String username, String password, int expiredSeconds) {
            //返回给前端的信息map
            HashMap<String, Object> map = new HashMap<>(10);

            if(StringUtils.isBlank(username)){
                map.put("usernameMsg","账户名不能为空");
                return map;
            }

            if(StringUtils.isBlank(password)){
                map.put("passwordMsg","账户名不能为空");
                return map;
            }

        User user = userMapper.findUserByUserName(username);
            if(user == null){
                map.put("usernameMsg","该账号不存在");
                return map;
            }
            if(user.getStatus() == 0){
                map.put("usernameMsg","该账号未激活");
                return map;
            }

            String string = CommunityUtil.parseByMd5(password, user.getSalt());
            if(! user.getPassword().equals(string)){
                map.put("passwordMsg","账号密码不正确");
                return map;
            }

            LoginTicket ticket = new LoginTicket();
            ticket.setUserId(user.getId());
            ticket.setTicket(CommunityUtil.generateUuid());
            ticket.setStatus(0);
            ticket.setExpired(new Date(System.currentTimeMillis() + 1000L * expiredSeconds));
            String ticketKey = RedisKeyUtil.getTicketKey(ticket.getTicket());
            try {
                redisTemplate.opsForValue().set(ticketKey,ticket,2, TimeUnit.DAYS);//凭证存储时间：2天
            } catch (Exception e) {
                logger.error("存入登录凭证失败+{} + {}",this.getClass().getName(),e.getMessage());
            }
        //loginTicketMapper.insertLoginTicket(ticket);
            map.put("ticket",ticket.getTicket());
            return map;
    }

    @Override
    public void logout(String ticket) {
        //loginTicketMapper.updateStatus(ticket, 1);
        String ticketKey = RedisKeyUtil.getTicketKey(ticket);
        LoginTicket loginTicket = (LoginTicket)redisTemplate.opsForValue().get(ticketKey);
        if(ObjectUtils.isNotEmpty(loginTicket)){
            loginTicket.setStatus(1);
            redisTemplate.opsForValue().set(ticketKey, loginTicket);
        }
    }

    @Override
    public LoginTicket findLoginTicket(String ticket) {
        //return loginTicketMapper.selectLoginTicket(ticket);
        String ticketKey = RedisKeyUtil.getTicketKey(ticket);
        return (LoginTicket)redisTemplate.opsForValue().get(ticketKey);
    }

    @Override
    public void updateHeader(int id, String headerUrl) {
        clearCache(id);
        userMapper.updateHeaderUrl(id, headerUrl);
    }

    @Override
    public void updatePassword(int id, String newPassword) {
        clearCache(id);
        userMapper.updatePassword(id, newPassword);
    }

    //优先从缓存中获取数据

    private User getUserInRedisById(int userId){
        logger.debug("优先从缓存中获取数据" + this.getClass().getName());
        String userKey = RedisKeyUtil.getUserKey(userId);
        return  (User) redisTemplate.opsForValue().get(userKey);
    }
    //缓存没有查询数据库，初始化缓存
    private User initCache(int userId){
        User user = userMapper.findUserById(userId);
        String userKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.opsForValue().set(userKey, user, 3600, TimeUnit.SECONDS);
        return user;
    }
    //更新时初始化清除缓存
    private void clearCache(int userId){
        String userKey = RedisKeyUtil.getUserKey(userId);
        redisTemplate.delete(userKey);
    }

    /**
     * 获取权限
     *
     * @param userId 用户id
     * @return {@link Collection<? extends GrantedAuthority>} 权限集合
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities(int userId) {
        User user = userMapper.findUserById(userId);
        String auth = "";
        switch(user.getType()){
            case 1 : auth =  "ROLE_" + CommunityConstant.AUTHORITY_ADMIN; break;
            case 2 : auth = "ROLE_" + CommunityConstant.AUTHORITY_MODERATOR; break;
            default : auth = "ROLE_" + CommunityConstant.AUTHORITY_USER;
        }
        return AuthorityUtils.commaSeparatedStringToAuthorityList(auth);
    }
}
